/**
 * Copyright (C) 2010 Cloudfarming <info@cloudfarming.nl>
 *
 * Licensed under the Eclipse Public License - v 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.cloudfarming.client.geoviewer;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;
import javax.swing.Action;

/**
 *
 * A layer represents a set of data to be shown on the
 * map in a layer.
 *
 *
 * @author Timon Veenstra
 */
public abstract class Layer<O extends LayerObject> {

    private static final Logger log = Logger.getLogger(Layer.class.getName());
    private final List<O> objects = new ArrayList<O>();
    private Palette palette;
    private final Category category;
    private final String name;
    public static final String PROPERTY_PALETTE = "palette";
    public static final String PROPERTY_INTER_ACTIVE = "interActive";
    public static final String PROPERTY_OBJECTS = "objects";
    private final PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);
    private boolean interActive = false;

    public Layer(Palette palette, Category category, String name) {
        this.palette = palette;
        this.category = category;
        this.name = name;
    }

    public Layer(Palette palette, Category category, String name, boolean interActive) {
        this.palette = palette;
        this.category = category;
        this.name = name;
        this.interActive = interActive;
    }

    /**
     * get a list of objects in the layer
     * Objects extend the LayerObject interface which contains
     * a geometry.
     *
     * @return
     */
    public List<O> getObjects() {
        return Collections.unmodifiableList(this.objects);
    }

    /**
     * Add a layerObject to the internal objects list
     *
     * @param object
     */
    public void addObject(O object) {
        List<O> objectsCopy = new ArrayList<O>(this.objects);
        this.objects.add(object);
        changeSupport.firePropertyChange(PROPERTY_OBJECTS, objectsCopy, this.objects);
    }

    /**
     * remove a layerObject from the internal objects list
     *
     * @param object
     */
    public void removeObject(O object) {
        if (this.objects.contains(object)) {
            List<O> objectsCopy = new ArrayList<O>(this.objects);
            this.objects.remove(object);
            changeSupport.firePropertyChange(PROPERTY_OBJECTS, objectsCopy, this.objects);

        }
    }

    /**
     * clear the objects list
     */
    public void clearObjects() {
        List<O> objectsCopy = new ArrayList<O>(this.objects);
        this.objects.clear();
        changeSupport.firePropertyChange(PROPERTY_OBJECTS, objectsCopy, this.objects);
    }

    /**
     * 
     * @param objectsToAdd
     */
    public void addObjects(List<O> objectsToAdd){
        List<O> objectsCopy = new ArrayList<O>(this.objects);
        this.objects.addAll(objectsToAdd);
        changeSupport.firePropertyChange(PROPERTY_OBJECTS, objectsCopy, this.objects);
    }

    /**
     * Category of the layer
     * 
     * @return
     */
    public Category getCategory() {
        return this.category;
    }

    /**
     * name of the layer
     *
     * @return
     */
    public String getName() {
        return this.name;
    }

    /**
     *
     * @param listener
     */
    public void addPropertyChangeListener(PropertyChangeListener listener) {
        changeSupport.addPropertyChangeListener(listener);
    }

    /**
     *
     * @param listener
     */
    public void removePropertyChangeListener(PropertyChangeListener listener) {
        changeSupport.removePropertyChangeListener(listener);
    }

    public final void setPalette(Palette palette) {
        assert palette != null;
        changeSupport.firePropertyChange(PROPERTY_PALETTE, this.palette, palette);
        this.palette = palette;
    }

    public Palette getPalette() {
        return this.palette;
    }

    /**
     * if a use can interact with the layer or not
     * 
     * @return
     */
    public boolean isInterActive() {
        return interActive;
    }

    /**
     *
     *
     * @param interActive
     */
    public void setInterActive(boolean interActive) {
        changeSupport.firePropertyChange(PROPERTY_INTER_ACTIVE, this.interActive, interActive);
        this.interActive = interActive;
    }

    /**
     * each layer implementation should implement its own way to update its data
     */
    public abstract void updateLayer();

    /**
     * override with actions for layerobjects
     * 
     * @return
     */
    public Action[] getActions(){
        return null;
    }
}
